package com.util.framework;



import com.util.framework.filter.Filter;
import com.util.framework.filter.GroupFilter;
import org.apache.commons.lang.StringUtils;

import java.lang.reflect.Method;
import java.util.*;

/***
 * 类描述: 伪Lambda表达式，
 * 1。快速检索集合中的某项元素
 * 2。对象映射
 * 3。集合排序
 *
 * @author FrodJiang
 * @date 18/03/2017
 */
public class Lambda<T> {
    private static Lambda obj;
    private List<T> listSource;
    private List<T> targetSource;
    private boolean isWhereUsed = false;

    /**
     * 每次创建都会新建一个对象
     * 1. 在一条Lambda语句中，不要出现两次source方法的调用
     *
     * @param source 数据源
     * @param <T>    数据源类型
     * @return
     */
    public static <T> Lambda<T> source(List<T> source) {
        obj = new Lambda<T>();
        obj.listSource = source;
        return obj;
    }

    /**
     * 条件语句
     *
     * @return
     * @throws LambdaException
     */
    public Lambda<T> where(Filter filter) throws LambdaException, DelegateException {
        if (this.listSource == null) {
            System.out.println("Lambda:数据源未初始化");
        }
        this.targetSource = new ArrayList<T>();
        for (T t : this.listSource) {
            boolean object = Boolean.parseBoolean(Delegate.invoke(filter, t).toString());
            if (object)
                this.targetSource.add(t);
        }
        isWhereUsed = true;
        return this;
    }

    /**
     * 返货一个对象
     *
     * @return
     * @throws LambdaException
     */
    public T first() throws LambdaException {
        return this.targetSource == null ? null : (T) this.targetSource.get(0);
    }

    /**
     * 返回一个对象，根据方法名和方法返回值
     *
     * @param fieldName 字段名
     * @param value
     * @return
     * @throws LambdaException
     */
    public T get(String fieldName, Object value) throws LambdaException {
        if (this.listSource == null) {
            System.out.println("Lambda:数据源未初始化");
            return null;
        }
        for (T t : this.listSource) {
            Method method = getMethodByFieldName(fieldName, t);
            try {
                if (method.invoke(t).equals(value)) {
                    return t;
                }
            } catch (Exception e) {
                throw new LambdaException(e.getMessage());
            }
        }
        return null;
    }

    /**
     * 返回一个列表
     *
     * @return
     * @throws LambdaException
     */
    public List<T> toList() throws LambdaException {
        if (isWhereUsed == false) {
            System.out.println("Lambda:请先调用where语句");
        }
        return this.targetSource.size() == 0 ? null : this.targetSource;
    }

    /**
     * 返回是否存在记录
     *
     * @return
     * @throws LambdaException
     */
    public boolean any(Filter filter) throws LambdaException, DelegateException {
        if (this.listSource == null) {
            return false;
        }
        List<T> list = new ArrayList<T>();
        for (T t : this.listSource) {
            boolean object = Boolean.parseBoolean(Delegate.invoke(filter, t).toString());
            if (object)
                return true;
        }
        return false;
    }

    public boolean any(String fieldName, Object value) throws LambdaException {
        if (this.listSource == null) {
            return false;
        }
        for (T t : this.listSource) {
            Method method = getMethodByFieldName(fieldName, t);
            try {
                if (value.equals(method.invoke(t))) {
                    return true;
                }
            } catch (Exception e) {
                throw new LambdaException(e.getMessage());
            }
        }
        return false;
    }

    public boolean all(String fieldName, Object value) throws LambdaException {
        if (this.listSource == null) {
            return false;
        }
        boolean flag = false;
        for (T t : this.listSource) {
            Method method = getMethodByFieldName(fieldName, t);
            try {
                if (method.invoke(t).equals(value)) {
                    flag = true;
                } else {
                    flag = false;
                    break;
                }
            } catch (Exception e) {
                throw new LambdaException(e.getMessage());
            }
        }
        return flag;
    }

    /**
     * 把集合转换为字符串，并以分隔符隔开
     *
     * @param separate 分隔符
     * @return
     * @throws LambdaException
     */
    public String join(String separate) throws LambdaException {
        if (this.listSource == null) {
            System.out.println("Lambda:数据源未初始化");
        }
        StringBuilder sb = new StringBuilder();
        for (T t : (this.targetSource != null ? this.targetSource : this.listSource)) {
            sb.append(t.toString() + separate);
        }
        return StringUtils.isBlank(sb.toString()) ? "" : sb.substring(0, sb.length() - 1);
    }

    /**
     * 把集合转换为字符串，并以分隔符隔开
     *
     * @param fieldName
     * @param separate
     * @return
     * @throws LambdaException
     */
    public String join(String fieldName, String separate) throws LambdaException {
        if (this.listSource == null) {
            System.out.println("Lambda:数据源未初始化");
        }
        StringBuilder sb = new StringBuilder();
        for (T t : this.listSource) {
            Method method = getMethodByFieldName(fieldName, t);
            try {
                sb.append(method.invoke(t) + separate);
            } catch (Exception e) {
                throw new LambdaException(e.getMessage());
            }
        }
        return StringUtils.isBlank(sb.toString()) ? "" : sb.substring(0, sb.length() - 1);
    }

    /**
     * 返回对象映射后的结果
     *
     * @param <To>
     * @return
     * @throws LambdaException
     */
    public <To> Lambda<T> mapper(Filter filter) throws LambdaException, DelegateException {
        if (this.listSource == null) {
            System.out.println("Lambda:数据源未初始化");
        }
        List<To> list = new ArrayList<To>();
        for (T t : (isWhereUsed ? this.targetSource : this.listSource)) {
            To to = (To) Delegate.invoke(filter, t);
            if (to != null) {
                list.add(to);
            }
        }
        this.targetSource = (List) list;
        return this;
    }

    public <K extends Comparable<K>, V> Map<K, List<V>> groupBy(GroupFilter filter) {
        if (this.listSource == null || this.listSource.isEmpty()) {
            System.out.println("分組集合不能為空!");
            return null;
        }
        if (filter == null) {
            System.out.println("分組依據接口不能為Null!");
            return null;
        }
        Iterator iter = this.listSource.iterator();
        Map<K, List<V>> map = new HashMap<K, List<V>>();
        while (iter.hasNext()) {
            V d = (V) iter.next();
            K t = (K) filter.groupby(d);
            if (map.containsKey(t)) {
                map.get(t).add(d);
            } else {
                List<V> list = new ArrayList<V>();
                list.add(d);
                map.put(t, list);
            }
        }
        return map;
    }

    /**
     * 根据字段名，返回对应的get方法。
     *
     * @param fieldName
     * @param t
     * @return
     * @throws LambdaException
     */
    private Method getMethodByFieldName(String fieldName, T t) throws LambdaException {
        Method targetMethod = null;
        for (Method method : t.getClass().getDeclaredMethods()) {
            if (method.getName().toLowerCase().equals("get" + fieldName.toLowerCase())) {
                try {
                    targetMethod = method;
                    break;
                } catch (Exception e) {
                    throw new LambdaException(e.getMessage());
                }
            }
        }
        if (targetMethod == null)
            throw new LambdaException("join：未找到字段");
        return targetMethod;
    }
}